/**
 * Copyright (c) 2011 Basil Shikin, VintageRadio Project
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.vintagephone.view.flat;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;

public class RadioDial
	extends View
{
	private static final int BACKGROUND_ANIMATION_STEP = 15;

	// Parent objects
	private final RadioDialController m_controller;
	
	// Controlled objects
	private final GestureDetector m_gestureDetector;
	
	private final RadioScreen[] m_screens;
		
	// State variables
	private int m_backgroundXOffset;
	private int m_targetBackgroundXOffset;
	private int m_backgroundStepDirection = 1;
	
	public RadioDial(RadioDialController radioDialController, final Context context) 
	{
		super(context);
		m_controller = radioDialController;
		
		final FlingGestureDetector flingDetector = new FlingGestureDetector( m_controller );
		m_gestureDetector = new GestureDetector( context, flingDetector );
		m_gestureDetector.setOnDoubleTapListener( new OnDoubleTapListener() {
            public boolean onDoubleTap(MotionEvent e)
            {
                android.os.Process.killProcess( android.os.Process.myPid() );  

                return false;
            }
            
            public boolean onDoubleTapEvent(MotionEvent e)  { return false; }
            public boolean onSingleTapConfirmed(MotionEvent e) { return false; }
        });
		
		setOnKeyListener( new OnKeyListener() {
			
			@Override
			public boolean onKey(View arg0, int arg1, KeyEvent event) {
				if ( event.getAction() != KeyEvent.ACTION_UP ) return true;
				
				if ( event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT )
				{
					m_controller.onSwipeLeft();
				}
				else if ( event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT)
				{
					m_controller.onSwipeRight();
				}
				else if ( event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP)
				{
					m_controller.onSwipeUp();
				}
				else if ( event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN)
				{
					m_controller.onSwipeDown();
				}
				
				
				return false;
			}
		});
		
		setFocusable( true );
		setFocusableInTouchMode( true );
		
		m_screens = new RadioScreen[ RadioDialController.SCREEN_COUNT ];
		for ( int i = 0; i < m_screens.length; i++ )
		{
		    m_screens[i] = new RadioScreen(i, m_controller, context);
		}
	}
	
	@Override
	public void draw(Canvas canvas) 
	{
		canvas.save();
		canvas.setDensity( Bitmap.DENSITY_NONE );
		
		float py = this.getHeight()/2.0f;
	    float px = this.getWidth()/2.0f;
	    canvas.rotate(180, px, py); 

	    boolean invalidate = false;
	    
		// Draw screens
	    for ( int i = 0; i < m_screens.length; i++ )
	    {
	        final RadioScreen screen = m_screens[i];
	        final int screenOffset = m_backgroundXOffset + i*screen.getWidth();
	        
	        // If screen is visible
	        if ( screenOffset + screen.getWidth() > 0 && screenOffset < getWidth() )
	        {
	            canvas.save();
	            
	            canvas.translate( screenOffset, 0 );
	            screen.draw( canvas );
	            
	            invalidate |= screen.prepareAnimationState();
	            
	            canvas.restore();
	        }
	        
	    }

		invalidate |= prepareAnimationState();
		
		if ( invalidate )
		{
			invalidate();
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) 
	{
        return m_gestureDetector.onTouchEvent(event);
	}

	@Override
	public boolean isClickable() 
	{
		return true;
	}

	@Override
	public boolean isInTouchMode() 
	{
		return true;
	}

	void showSong( int songNumber, int screen)
	{
		m_screens[ screen ].showSong(songNumber);

		invalidate();
	}
			
	void showScreen( int number )
	{
		final int screenOffset = calculateBackgroundOffset( number );
		
		if ( m_backgroundXOffset == screenOffset) return;
		
		if ( screenOffset > m_backgroundXOffset )
		{
			m_backgroundStepDirection = BACKGROUND_ANIMATION_STEP;
		}
		else
		{
			m_backgroundStepDirection = -BACKGROUND_ANIMATION_STEP;
		}
		
		m_targetBackgroundXOffset = screenOffset;
		
		invalidate();
	}
	
	private int calculateBackgroundOffset(int number) 
	{
		return -number*m_screens[number].getWidth();
	}
	
	
	private boolean prepareAnimationState() 
	{
		boolean bgNeedsRepaint = false;
		if ( isMovingBackground()  )
		{
			m_backgroundXOffset += m_backgroundStepDirection;
			
			bgNeedsRepaint = true;
		}
		else
		{
			if ( m_backgroundXOffset != m_targetBackgroundXOffset )
			{
				bgNeedsRepaint = true;
			}

			m_backgroundXOffset = m_targetBackgroundXOffset;
		}
		
		return bgNeedsRepaint;
	}
	
	private boolean isMovingBackground() 
	{
		return Math.abs( m_targetBackgroundXOffset - m_backgroundXOffset ) > BACKGROUND_ANIMATION_STEP/2;
	}
	
	 private static class FlingGestureDetector 
	 	extends GestureDetector.SimpleOnGestureListener 
	 	{
		 	private static final int SWIPE_X_MIN_DISTANCE = 80;
		 	private static final int SWIPE_Y_MIN_DISTANCE = 40;
		    private static final int SWIPE_MAX_OFF_PATH = 250;
		    private static final int SWIPE_X_THRESHOLD_VELOCITY = 60;
		    private static final int SWIPE_Y_THRESHOLD_VELOCITY = 60;
		    
		    private final RadioDialController m_controller;
		    
		    
	        FlingGestureDetector(RadioDialController controller) 
	        {
				m_controller = controller;
			}

			@Override
	        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
	        {
	            try 
	            {
	                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) return false;
	                
	                if(e1.getX() - e2.getX() > SWIPE_X_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_X_THRESHOLD_VELOCITY) 
	                {
	                	m_controller.onSwipeLeft();
	                }  
	                else if (e2.getX() - e1.getX() > SWIPE_X_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_X_THRESHOLD_VELOCITY) 
	                {
	                	m_controller.onSwipeRight();
	                }
	                else if(e1.getY() - e2.getY() > SWIPE_Y_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_Y_THRESHOLD_VELOCITY) 
	                {
	                	m_controller.onSwipeDown();
	                }  
	                else if (e2.getY() - e1.getY() > SWIPE_Y_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_Y_THRESHOLD_VELOCITY) 
	                {
	                	m_controller.onSwipeUp();	                	
	                }
	            } 
	            catch (Exception e) {}
	            
	            return super.onFling(e1, e2, velocityX, velocityY);
	        }

			@Override
			public boolean onDown(MotionEvent e) {
			    
				return true;
			}
	    }
}
